/** 可以缓存函数；
 * 高阶函数
 * @param func 函数
 * @returns 函数
 */
export function memoize(func: Function, resolver?: Function) {
  const memoized = function (...args: any[]) {
    const key = resolver ? resolver.apply(this, ...args) : args[0];
    if (memoized.cache.has(key)) {
      return memoized.cache.get(key);
    }
    const result = func.apply(this, args);
    return result;
  };
  memoized.cache = new WeakMap();
  return memoized;
}

interface IObj {
  [index: string]: any;
}

/** 统计对象数组中某个属性值出现的次数；
 *
 * @param arr
 * @param fn
 * @returns
 */
export function countBy(arr: IObj[], fn: (item: IObj) => string) {
  const result = {};
  for (const item of arr) {
    const key = fn(item);
    result[key] ? result[key]++ : (result[key] = 1);
  }
  return result;
}

const users = [
  { user: "barney", age: 36, active: true },
  { user: "fred", age: 40, active: false },
  { user: "pebbles", age: 15, active: true },
];

const count = countBy(users, (item) => item.active);
console.log(count);

/** 函数柯里化
 *
 * @param fn
 * @param bindArgs
 * @returns
 */
export function currying(fn: Function, ...bindArgs: any[]) {
  return (...args: any[]) => {
    const allArgs = [...bindArgs, ...args];
    if (allArgs.length < fn.length) {
      return currying(fn, ...allArgs);
    } else {
      return fn(...allArgs);
    }
  };
}

/** 对象数组去重
 *
 * @param arr 对象数组
 * @returns 去重的对象数组
 */
export function arrayUnique(arr: any[]) {
  const newArr = [...arr];
  for (let i = 0, len = arr.length; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (equals(arr[i], arr[j])) {
        newArr.splice(j, 1);
        j--;
      }
    }
  }
  return newArr;
}
/** 是否相同
 *
 * @param val1
 * @param val2
 * @returns
 */
function equals(val1: any, val2: any) {
  if (!isObject(val1) || !isObject(val2)) {
    return Object.is(val1, val2);
  }
  if (val1 === val2) return true;
  const val1Keys = Object.keys(val1);
  const val2Keys = Object.keys(val2);
  if (val1Keys.length !== val2Keys.length) return false;
  for (const key of val1Keys) {
    if (!val2Keys.includes(key)) return false;
    const res = equals(val1[key], val2[key]);
    if (!res) return false;
  }
  return true;
}
/** 是否是对象
 *
 * @param val
 * @returns
 */
const isObject = (val: any) => val !== null && typeof val === "object";

export function sum(nums: number[]) {
  function f(i: number) {
    return i >= nums.length ? 0 : nums[i] + f(i + 1);
  }
  return f(0);
}

/** 带缓存的深度克隆，避免无限递归；
 *
 * @param val
 * @returns
 */
export function deepClone(val: any) {
  const cache = new WeakMap();
  function clone(val: any) {
    if (val === null || typeof val !== "object") {
      return val;
    }
    if (val instanceof Date) {
      return new Date(val.getTime());
    }
    if (val instanceof RegExp) {
      return new RegExp(val);
    }
    if (cache.has(val)) {
      return cache.get(val);
    }
    const res = Array.isArray(val) ? [] : {};
    cache.set(val, res);
    for (const key in val) {
      if (val.hasOwnProperty(key)) {
        res[key] = clone(val[key]);
      }
    }
    return res;
  }
  return clone(val);
}

/** 数组根据中文字典（拼音）排序
 *
 * @param strs
 * @returns
 */
export function CNSort(strs: string[]) {
  return strs.sort((a, b) => a.localeCompare(b, "zh-CN"));
}
